﻿using System;
using System.Collections.Generic;
using Afru.Components.Messaging;

namespace Afru
{
    public class Component
    {
        #region Variables

        #region Private variables

        string name;
        bool active = true; //Can the component update?
        bool visible = true;//Can the componenet draw?
        GameScreen parent; //The gamescreen that this component belongs to
        int drawOrder = 0; //The order that the component is drawn in[Higher number = drawn later]
        bool loaded = false;//Has the component loaded all its data?
        Engine engine = null;

        // Keep track of the number of each type of component that have been
        // created, so we can generate a unique name for each component
        static Dictionary<Type, int> componentTypeCounts = new Dictionary<Type, int>();

        #endregion

        #region Public variables

        public string Name
        {
            get { return name; }
            set
            {
                // Make sure we have a valid name before allowing it to be
                // changed
                if (string.IsNullOrEmpty(value))
                    throw new Exception("Component name must not be null "
                        + "and be greater than 0 characters");
                else
                    name = value;
            }
        }

        public GameScreen Parent
        {
            get { return parent; }
            set
            {
                if (parent != null)
                    parent.RemoveComponent(this);

                if (parent != value)
                {
                    parent = value;

                    if (value != null)
                        parent.AddComponent(this);
                }
            }
        }

        public int DrawOrder
        {
            get { return drawOrder; }
            set
            {
                this.drawOrder = value;

                if (Parent != null)
                    Parent.PutComponentsInOrder(this);
            }
        }

        public bool Loaded { get { return loaded; } }

        public bool Active { get { return active; } set { active = value; } }
        public bool Visible { get { return visible; } set { visible = value; } }

        public Engine ParentEngine { set { engine = value; } get { return engine; } }

        #endregion

        #endregion

        #region Constructor

        public Component()
        {
            generateUniqueName();
        }

        #endregion

        #region Class Functions

        #region Overrideable functions

        public virtual void OnRemove()
        {

        }

        //LoadGameScreen() checks the variable loaded. If loaded is false, Load() is called
        public void LoadComponent()
        {
            if (!loaded)
                Load();

            loaded = true;
        }

        //Load() is used by the class's children 
        protected virtual void Load()
        {
            ParentEngine.Messaging.MessageHandler += new MessageReceivedEventHandler(ReceiveMessage);
        }

        public virtual void Update()
        {
        }

        public virtual void Draw()
        {

        }

        public virtual void ReceiveMessage(AMessage Message)
        {
            //TODO: disposal?
        }

        #endregion

        protected void AddComponent(Component component)
        {
            Parent.AddComponent(component);
        }

        // Generate a unique name for the component simply using the type name
        // and the number of that type that have been created
        private void generateUniqueName()
        {
            Type t = this.GetType();

            if (!componentTypeCounts.ContainsKey(t))
                componentTypeCounts.Add(t, 0);

            componentTypeCounts[t]++;

            this.name = t.Name + componentTypeCounts[t];
        }

        #endregion

        
    }
}
